package cc.tuhaolicai.mt.user.mobile.business.handler;

import cc.tuhaolicai.mt.user.mobile.business.exception.NotTryChainException;
import cc.tuhaolicai.mt.user.mobile.business.model.Node;
import cc.tuhaolicai.mt.user.mobile.business.model.Workflow;
import cc.tuhaolicai.mt.user.mobile.business.util.WorkflowUtil;
import cc.tuhaolicai.mt.user.mobile.model.Chain1Model;
import cc.tuhaolicai.mt.user.mobile.tool.ToolGen;
import cc.tuhaolicai.mt.user.mobile.tool.ToolMongo;
import com.google.common.collect.Maps;
import pro.tools.data.text.ToolJson;
import pro.tools.data.text.ToolStr;

import java.util.Map;

/**
 * 业务链基类
 *
 * @author chenli
 * @create 2017-10-11
 */
public abstract class BusinessHandler {

    /**
     * 下一个执行的业务
     */
    private BusinessHandler nextHandler = null;

    public boolean check = true;

    /**
     * 执行时参数
     */
    private Map<String,Object> params = Maps.newHashMap();

    /**
     * 业务名称
     */
    private String name;

    /**
     * 业务流水号
     */
//    protected String orderNo;
    /**
     * 所属业务链
     */
    private Workflow workflow;

    /**
     * 当前业务排序
     * 从0开始计数
     */
    private int sort = 0;

    /**
     * 当前业务执行开始时参数
     */
    private Map<String,Object> startParams = Maps.newHashMap();

    /**
     * 当前业务执行后参数
     */
    private Map<String,Object> stopParams = Maps.newHashMap();

    public BusinessHandler() {

    }

    /**
     * 添加下一个业务
     * @param nextHandler：下一个业务
     */
    public BusinessHandler(BusinessHandler nextHandler) {
        this.nextHandler = nextHandler;
    }

    /**
     * 当前业务名称
     * @param name：
     */
    public BusinessHandler(String name){
        this.name = name;
    }

    /**
     * 执行业务
     */
    public abstract void execute(Map<String,Object> params);

    public void checkHandler(BusinessHandler handler){
        if(ToolStr.isBlank(handler.getName()) || "null".equals(handler.getName())){
            throw new NotTryChainException("handler名称不能为空");
        }
        if(handler.nextHandler != null){
            checkHandler(handler.nextHandler);
        }
    }

    public void start(Map<String,Object> params,Workflow workflow) throws NotTryChainException{
        if(check){
            checkHandler(this);
        }

        setWorkflow(workflow);
        boolean repeatExecute = false;
        this.params.putAll(params);
        //记录执行前数据
        startParams.putAll(this.params);
        Node node = WorkflowUtil.findWorkflowNode(this.workflow,this.sort);//ToolMongo.findOne(new Node().setOrderNo(workflow.getOrderNo()).setSort(this.sort));
        if(node == null){
            node = WorkflowUtil.buildWorkflowNode(this.name, this.sort, ToolJson.mapToJson(this.startParams),this.getClass().getName());
        }else{
            repeatExecute = true;
            node.setStartParams(ToolJson.mapToJson(this.startParams));
        }

        try{
            execute(this.params);
        }catch (NotTryChainException notTry){
            //记录执行后数据
            stopParams.putAll(params);
            node.setStatus(1);
            node.setStopParams(ToolJson.mapToJson(this.stopParams));
            node.setResult("执行成功");
            this.workflow.setResult("该业务链执行成功,后续业务不需要操作");
            this.workflow.setStatus(1);
            save(repeatExecute,node);
            throw notTry;
        } catch (Exception e){
            //记录异常数据
            stopParams.putAll(params);
            node.setStatus(2);
            node.setStopParams(ToolJson.mapToJson(this.stopParams));
            this.workflow.setResult(node.getNodeName()+"执行失败");
            node.setResult("执行失败");
            this.workflow.setStatus(2);
            if(!repeatExecute){
                WorkflowUtil.addWorkflowNode(this.workflow,node);
                createNode(this.workflow,this.nextHandler);
                insert();
            }else{
                WorkflowUtil.updateWorkflowNode(this.workflow,node);
                update();
            }
            throw e;
        }
        //记录执行后数据
        stopParams.putAll(params);
        node.setStatus(1);
        node.setStopParams(ToolJson.mapToJson(this.stopParams));
        node.setResult("执行成功");
        if(nextHandler==null){
            this.workflow.setResult("执行成功");
            this.workflow.setStatus(1);
            save(repeatExecute,node);
        }else{
            WorkflowUtil.addWorkflowNode(this.workflow,node);
            nextHandler.setCheck(false);
            nextHandler.start(this.params,this.workflow);
        }
    }

    public void setNextHandler(BusinessHandler nextHandler) {
        nextHandler.setWorkflow(this.workflow);
        nextHandler.setSort(this.sort+1);
        this.nextHandler = nextHandler;
    }

    public void setName(String name){
        this.name = name;
    }

    public void addParams( Map<String,Object> params){
        this.params.putAll(params);
    }

    public void addParams(String key,Object value){
        this.params.put(key,value);
    }

    private void setWorkflow(Workflow workflow){
        this.workflow = workflow;
    }

    public void setSort(Integer sort){
        this.sort = sort;
    }

//    public void setOrderNo(String orderNo){
//        this.orderNo = orderNo;
//    }

    private void save(boolean repeatExecute,Node node){
        if(!repeatExecute){
            WorkflowUtil.addWorkflowNode(this.workflow,node);
            insert();
        }else{
            WorkflowUtil.updateWorkflowNode(this.workflow,node);
            update();
        }
    }

    private void insert() {
        this.workflow.setId(ToolGen.genId(Chain1Model.class,"id"));
        ToolMongo.insertOne(this.workflow);
//        Thread thread = new Thread(() -> ToolMongo.insertOne(this.workflow));
//        thread.setName(this.workflow.getName() + System.currentTimeMillis());
//        thread.start();
    }

    private void update(){
        ToolMongo.updateOne(new Workflow().setOrderNo(this.workflow.getOrderNo()),this.workflow);
//        Thread thread = new Thread(() -> ToolMongo.updateOne(new Workflow().setOrderNo(this.workflow.getOrderNo()),this.workflow));
//        thread.setName(this.workflow.getName() + System.currentTimeMillis());
//        thread.start();
    }

    private void createNode(Workflow workflow,BusinessHandler handler){
        Node node = WorkflowUtil.buildWorkflowNode(handler.name, handler.sort, ToolJson.mapToJson(handler.startParams),handler.getClass().getName());
        WorkflowUtil.addWorkflowNode(workflow,node);
        if(handler.nextHandler != null){
            createNode(workflow,handler.nextHandler);
        }
    }

    public BusinessHandler getNextHandler() {
        return nextHandler;
    }

    public Map<String, Object> getParams() {
        return params;
    }

    public String getName() {
        return name;
    }

    public Workflow getWorkflow() {
        return workflow;
    }

    public int getSort() {
        return sort;
    }

    public Map<String, Object> getStartParams() {
        return startParams;
    }

    public Map<String, Object> getStopParams() {
        return stopParams;
    }

    public void setCheck(boolean check){
        this.check = check;
    }

}